package com.njbw.train.common.util;

import cn.hutool.core.util.IdUtil;

/**
 * 封装 hutool 雪花算法
 *
 * 为每个数据中心和机器编号，保证每台机器生成的 ID 不重复
 * snowflake 算法生成的 ID 是一个 64 位的 long 类型数字，结构如下：
 * 第一位：0，未使用
 * 41 bit - 时间戳     10 bit -  机器 ID    12 bit - 序列号（为了解决同一毫秒内进来多个序列号的问题，从 1 开始，依次递增）
 * 机器 ID 就是 5 位数据中心 ID + 5 位机器 ID
 * 序列号：一个毫秒内最多生成 4096 个 ID
 * 雪花算法问题：数据中心、机器 ID 怎么设置？利用 redis 自增序列，或者利用数据库，为每台机器分配 workId，保存 ip 和 workId 的映射关系
 * 雪花算法问题：如何保证生成的 ID 不会重复？利用 redis 原子操作 INCRBY
 * 雪花算法问题：如何保证生成的 ID 有序递增？利用 redis 原子操作 INCRBY
 * 时钟回拨问题：机器时间是 3 点，北京时间是 2 点，此时需要把机器时间调回 2 点，那么 2 点 ~ 3 点的 ID 会重新再生成一遍（2 点 ~ 3 点不启动就能解决该问题了）
 *
 * 特点：
 *      全局唯一，有序增长，生长效率高
 *      可反解生成 ID 信息，方便排查问题
 */
public class SnowUtil {

    // 可以启动的时候直接申请，这样每一台的就不一样了
    private static long dataCenterId = 1; // 数据中心
    private static long workerId = 1; // 机器标识

    public static long getSnowFlakeNextId() {
        return IdUtil.getSnowflake(workerId, dataCenterId).nextId();
    }

    public static String getSnowFlakeNextIdStr() {
        return IdUtil.getSnowflake(workerId, dataCenterId).nextIdStr();
    }
}
